package l1j.server.server.clientpackets;

import static l1j.server.server.model.skill.L1SkillId.EXP_UP;
import static l1j.server.server.model.skill.L1SkillId.SHAPE_CHANGE;
import static l1j.server.server.model.skill.L1SkillId.STATUS_BLUE_POTION;
import static l1j.server.server.model.skill.L1SkillId.STATUS_BRAVE;
import static l1j.server.server.model.skill.L1SkillId.STATUS_CHAT_PROHIBITED;
import static l1j.server.server.model.skill.L1SkillId.STATUS_ELFBRAVE;
import static l1j.server.server.model.skill.L1SkillId.STATUS_HASTE;
import static l1j.server.server.model.skill.L1SkillId.MapTimer;
import static l1j.server.server.model.skill.L1SkillId.STATUS_THIRD_SPEED;
import static l1j.server.server.model.skill.L1SkillId.STATUS_THIRD_SPEED2;
import static l1j.server.server.model.skill.L1SkillId.STATUS_THIRD_SPEED3;
import static l1j.server.server.model.skill.L1SkillId.STATUS_THIRD_SPEED4;
import static l1j.server.server.model.skill.L1SkillId.Online_Bonus;
import static l1j.server.server.model.skill.L1SkillId.惡魔的香水;
import static l1j.server.server.model.skill.L1SkillId.狂暴打擊;
import static l1j.server.server.model.skill.L1SkillId.狩獵專長;
import static l1j.server.server.model.skill.L1SkillId.賞金獵人;
import static l1j.server.server.model.skill.L1SkillId.鋼鐵防禦;
import static l1j.server.server.model.skill.L1SkillId.蒜頭雞湯;
import static l1j.server.server.model.skill.L1SkillId.烏骨雞湯;
import static l1j.server.server.model.skill.L1SkillId.人參雞湯;
import static l1j.server.server.model.skill.L1SkillId.checkDeleteItem;
import static l1j.server.server.model.skill.L1SkillId.ATTRACT_MONSTER;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.opqlo.SuperNGChat;
import l1j.opqlo.NewSystem.A_ColorMessage;
import l1j.opqlo.NewSystem.Extension.CrackTime;
import l1j.opqlo.NewSystem.地圖限時.MapTimeTable;
import l1j.opqlo.Server.QuitGame;
import l1j.opqlo.Server.L1World.L1World;
import l1j.opqlo.Server.L1World.WorldClan;
import l1j.opqlo.Server.L1World.WorldSummons;
import l1j.opqlo.Server.L1World.WorldWar;
import l1j.opqlo.Timer.Controler.Server.ServerWarExecutor;
import l1j.opqlo.防暴等措施.快速50級;
import l1j.server.Config;
import l1j.server.DatabaseFactory;
import l1j.server.GameServer.GameServer;
import l1j.server.Thread.GeneralThreadPool;
import l1j.server.echo.ClientThread;
import l1j.server.server.ActionCodes;
import l1j.server.server.datatables.CastleTable;
import l1j.server.server.datatables.CharObjidTable;
import l1j.server.server.datatables.CharacterTable;
import l1j.server.server.datatables.GetBackRestartTable;
import l1j.server.server.datatables.ItemTable;
import l1j.server.server.datatables.SkillsTable;
import l1j.server.server.datatables.lock.CharSkillReading;
import l1j.server.server.datatables.lock.CharacterConfigReading;
import l1j.server.server.datatables.lock.ClanEmblemReading;
import l1j.server.server.model.Getback;
import l1j.server.server.model.L1CastleLocation;
import l1j.server.server.model.L1Clan;
import l1j.server.server.model.L1PolyMorph;
import l1j.server.server.model.L1Quest;
import l1j.server.server.model.L1War;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.Instance.L1SummonInstance;
import l1j.server.server.model.map.L1Map;
import l1j.server.server.model.skill.L1BuffUtil;
import l1j.server.server.model.skill.L1SkillId;
import l1j.server.server.model.skill.L1SkillUse;
import l1j.server.server.serverpackets.S_AddSkill;
import l1j.server.server.serverpackets.S_Bookmarks;
import l1j.server.server.serverpackets.S_CharTitle;
import l1j.server.server.serverpackets.S_CharVisualUpdate;
import l1j.server.server.serverpackets.S_CharacterConfig;
import l1j.server.server.serverpackets.S_Emblem;
import l1j.server.server.serverpackets.S_InitialAbilityGrowth;
import l1j.server.server.serverpackets.S_InvList;
import l1j.server.server.serverpackets.S_Karma;
import l1j.server.server.serverpackets.S_LoginResult;
import l1j.server.server.serverpackets.S_MPUpdate;
import l1j.server.server.serverpackets.S_Mail;
import l1j.server.server.serverpackets.S_MapID;
import l1j.server.server.serverpackets.S_OwnCharPack;
import l1j.server.server.serverpackets.S_OwnCharStatus;
import l1j.server.server.serverpackets.S_PacketBox;
import l1j.server.server.serverpackets.S_PacketBoxConfig;
import l1j.server.server.serverpackets.S_PinkName;
import l1j.server.server.serverpackets.S_SPMR;
import l1j.server.server.serverpackets.S_ServerMessage;
import l1j.server.server.serverpackets.S_SkillBrave;
import l1j.server.server.serverpackets.S_SkillHaste;
import l1j.server.server.serverpackets.S_SkillIconExp;
import l1j.server.server.serverpackets.S_SkillIconGFX;
import l1j.server.server.serverpackets.S_SkillSound;
import l1j.server.server.serverpackets.S_Sound;
import l1j.server.server.serverpackets.S_SummonPack;
import l1j.server.server.serverpackets.S_SystemMessage;
import l1j.server.server.serverpackets.S_Unknown1;
import l1j.server.server.serverpackets.S_Unknown2;
import l1j.server.server.serverpackets.S_War;
import l1j.server.server.serverpackets.S_Weather;
import l1j.server.server.templates.L1BookMark;
import l1j.server.server.templates.L1Castle;
import l1j.server.server.templates.L1Config;
import l1j.server.server.templates.L1EmblemIcon;
import l1j.server.server.templates.L1GetBackRestart;
import l1j.server.server.templates.L1Item;
import l1j.server.server.templates.L1Skills;
import l1j.server.server.templates.L1UserSkillTmp;
import l1j.server.server.utils.Random;
import l1j.server.server.utils.SQLUtil;

// Referenced classes of package l1j.server.server.clientpackets:
// ClientBasePacket
//
public class C_LoginToServer extends ClientBasePacket {
	//取得目前時間
	//把要測試的程式放到startTime後面
	private static final String C_LOGIN_TO_SERVER = "[C] C_LoginToServer";
	private static Logger _log = Logger.getLogger(C_LoginToServer.class.getName());

	/**
	 * 所在座標位置資料判斷
	 *
	 * @param pc
	 */
	private void BackRestart(final L1PcInstance pc){
		try {

			// 指定MAP回村設置
			final GetBackRestartTable gbrTable = GetBackRestartTable.getInstance();
			final L1GetBackRestart[] gbrList = gbrTable.getGetBackRestartTableList();
			for (final L1GetBackRestart gbr : gbrList) {
				if (pc.getMapId() == gbr.getArea()) {
					pc.setX(gbr.getLocX());
					pc.setY(gbr.getLocY());
					pc.setMap(gbr.getMapId());
					break;
				}
			}

			// altsettings.propertiesでGetBackがtrueなら街に移動させる
			/*	if(pc.isGm()){
		pc.setX(32745);
		pc.setY(32807);
		pc.setMap((short)99);

	}else */if (Config.GET_BACK) {
		final int[] loc = Getback.GetBack_Location(pc, true);
		pc.setX(loc[0]);
		pc.setY(loc[1]);
		pc.setMap((short) loc[2]);

	}

	// 戰爭區域回村設置
	final int castle_id = L1CastleLocation.getCastleIdByArea(pc);
	if (castle_id > 0 ) {
		//L1CastleLocation.getCastleIdByArea(this);
		//		if (WarTimeController.getInstance().isNowWar(castle_id)) {
		if(L1CastleLocation.getCastleIdByArea(pc) >0){

			final L1Clan clan = WorldClan.get().getClan(pc.getClanname());
			if (clan != null) {
				if (clan.getCastleId() != castle_id) {
					// 城主クランではない
					int[] loc = new int[3];
					loc = L1CastleLocation.getGetBackLoc(castle_id);
					pc.setX(loc[0]);
					pc.setY(loc[1]);
					pc.setMap((short) loc[2]);
				}
			} else {
				// クランに所属して居ない場合は帰還
				int[] loc = new int[3];
				loc = L1CastleLocation.getGetBackLoc(castle_id);
				pc.setX(loc[0]);
				pc.setY(loc[1]);
				pc.setMap((short) loc[2]);
			}
		}
	}
	final L1Map map = pc.getMap();
	// 位置可通行中斷線程
	if (!map.isInMap(pc.getX(), pc.getY())) {
		//1784	32797	32803

		pc.setX(32767);
		pc.setY(32803);
		pc.setMap((short) 1784);

	}
		} catch (final Exception e) {
			_log.log(Level.WARNING,e.getLocalizedMessage(), e);
		}

	}

	private void bookmarks(final L1PcInstance pc) {

		Connection con = null;
		PreparedStatement pstm = null;
		ResultSet rs = null;
		try {

			con = DatabaseFactory.get().getConnection();
			pstm = con.prepareStatement("SELECT * FROM character_teleport WHERE char_id=? ORDER BY name ASC");
			pstm.setInt(1, pc.getId());

			rs = pstm.executeQuery();
			while (rs.next()) {
				final L1BookMark bookmark = new L1BookMark();
				bookmark.setId(rs.getInt("id"));
				bookmark.setCharId(rs.getInt("char_id"));
				bookmark.setName(rs.getString("name"));
				bookmark.setLocX(rs.getInt("locx"));
				bookmark.setLocY(rs.getInt("locy"));
				bookmark.setMapId(rs.getShort("mapid"));
				final S_Bookmarks s_bookmarks = new S_Bookmarks(bookmark.getName(),bookmark.getMapId(), bookmark.getId());
				pc.addBookMark(bookmark);
				pc.sendPackets(s_bookmarks);

			}

		} catch (final SQLException e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
		} finally {
			SQLUtil.close(rs);
			SQLUtil.close(pstm);
			SQLUtil.close(con);
		}
	}
	private void buff(final L1PcInstance pc) {
		Connection con = null;
		PreparedStatement pstm = null;
		ResultSet rs = null;
		try {
			con = DatabaseFactory.get().getConnection();
			pstm = con.prepareStatement("SELECT * FROM character_buff WHERE char_obj_id=?");
			pstm.setInt(1, pc.getId());
			rs = pstm.executeQuery();
			while (rs.next()) {
				final int skillid = rs.getInt("skill_id");
				final int remaining_time = rs.getInt("remaining_time");
				switch(skillid){
				case SHAPE_CHANGE:// 変身
					L1PolyMorph.doPoly(pc, rs.getInt("poly_id"), remaining_time,L1PolyMorph.MORPH_BY_LOGIN);
					break;
				case STATUS_BRAVE:// ブレイブ ポーション等
					pc.sendPackets(new S_SkillBrave(pc.getId(), 1,remaining_time));
					pc.broadcastPacketAll(new S_SkillBrave(pc.getId(), 1, 0));
					pc.setBraveSpeed(1);
					break;
				case STATUS_ELFBRAVE:// エルヴンワッフル
					pc.sendPackets(new S_SkillBrave(pc.getId(), 3,remaining_time));
					pc.broadcastPacketAll(new S_SkillBrave(pc.getId(), 3, 0));
					pc.setBraveSpeed(1);
					pc.setSkillEffect(skillid, remaining_time * 1000);
					break;
				case STATUS_HASTE:// グリーン ポーション
					pc.sendPackets(new S_SkillHaste(pc.getId(), 1,remaining_time));
					pc.broadcastPacketAll(new S_SkillHaste(pc.getId(), 1, 0));
					pc.setMoveSpeed(1);
					pc.setSkillEffect(skillid, remaining_time * 1000);
					break;
				case STATUS_BLUE_POTION:// ブルーポーション
					pc.sendPackets(new S_SkillIconGFX(34, remaining_time));
					pc.setSkillEffect(skillid, remaining_time * 1000);
					break;
				case STATUS_CHAT_PROHIBITED: // チャット禁止
					pc.sendPackets(new S_SkillIconGFX(36, remaining_time));
					pc.setSkillEffect(skillid, remaining_time * 1000);
					final SuperNGChat r = new SuperNGChat(pc , remaining_time);
					GeneralThreadPool.getInstance().schedule(r, 500);
					break;
				case L1SkillId.PC_IsPinkName:
					pc.setSkillEffect(skillid, remaining_time * 1000);
					pc.setPinkName(true);
					pc.sendPackets(new S_PinkName(pc.getId(),remaining_time));
					break;
				case STATUS_THIRD_SPEED://opqlo 3段加速
					L1BuffUtil.supperSpeed(pc, remaining_time * 1000 , (byte) 1);
					break;
				case STATUS_THIRD_SPEED2: // 4段加速
					L1BuffUtil.supperSpeed(pc, remaining_time * 1000 , (byte) 2);
					break;
				case STATUS_THIRD_SPEED3://opqlo 4.5段加速
					L1BuffUtil.supperSpeed(pc, remaining_time * 1000 , (byte) 3);
					break;
				case STATUS_THIRD_SPEED4://opqlo 5段加速
					L1BuffUtil.supperSpeed(pc, remaining_time * 1000 , (byte) 4);
					break;
				case EXP_UP:
					pc.setSkillEffect(skillid, remaining_time * 1000);
					pc.sendPackets(new S_SystemMessage("經驗加"+pc.getExpRate+"倍還剩下:[ "+pc.getSkillEffectTimeSec(EXP_UP)+" ]秒。"));
					pc.set_food((short) 225);
					pc.sendPackets(new S_PacketBox(S_PacketBox.FOOD, (short) 225));
					pc.sendPackets(new S_PacketBox(53, 7, remaining_time));//opqlo 經驗狀態時間顯示
					pc.sendPackets(new S_PacketBox(S_PacketBox.FOOD, (short) 225));
//					pc.sendPackets(new S_PacketBox(53, 23, remaining_time));//opqlo 經驗狀態時間顯示
					break;
				case 蒜頭雞湯:
					pc.setSkillEffect(skillid, remaining_time * 1000);
					pc.sendPackets(new S_SystemMessage("體魄更為強健，全部攻擊力上升 15%。"));
					pc.sendPackets(new S_SkillSound(pc.getId() , 2425));
					break;
				case 烏骨雞湯:
					pc.setSkillEffect(skillid, remaining_time * 1000);
					pc.sendPackets(new S_SystemMessage("身體更為硬朗，全部防禦力上升 15%。"));
					pc.sendPackets(new S_SkillSound(pc.getId() , 2426));
					break;
				case 人參雞湯:
					pc.setSkillEffect(skillid, remaining_time * 1000);
					pc.sendPackets(new S_SystemMessage("氣血更為流暢，HP、MP上升 30%。"));
					pc.sendPackets(new S_SystemMessage("氣血更為流暢，HP、MP上升 30%。"));
					pc.setExtraHp((int) (pc.getBaseMaxHp() *0.3));
					pc.setExtraMp((int) (pc.getBaseMaxMp() *0.3));
					pc.addMaxHp(pc.getExtraHp());
					pc.addMaxMp(pc.getExtraMp());
					pc.setCurrentHp(pc.getCurrentHp()-1);
					if (pc.isInParty()) { // パーティー中
						pc.getParty().updateMiniHP(pc);
					}
					pc.sendPackets(new S_MPUpdate(pc.getCurrentMp(), pc.getMaxMp()));
					pc.sendPackets(new S_SkillSound(pc.getId() , 2427));
					break;
				case ATTRACT_MONSTER:
					pc.setSkillEffect(skillid, remaining_time * 1000);
					pc.sendPackets(new S_SystemMessage("\\aD散發出特殊氣味，吸引怪物追打["+remaining_time+"]秒。"));
					pc.sendPacketsX8(new S_Sound(165));
					pc.sendPacketsX8(new S_SkillSound(pc.getId(),4627));
					break;
				case 惡魔的香水:
					pc.addDroprate(0.5);
					pc.add金幣率(0.5);
					pc.setSkillEffect(惡魔的香水, (remaining_time*1000));//30分鐘
					pc.sendPackets(new S_SystemMessage("\\aH你向撒旦奉獻了180張積分卷，獲得掉寶、"));
					pc.sendPackets(new S_SystemMessage("\\aH金幣倍率 +50%的效果，持續"+remaining_time+"秒。"));
					pc.sendPacketsX8(new S_SkillSound(pc.getId() , 422));
					pc.sendPacketsX8(new S_SkillSound(pc.getId() , 437));
					break;
				default:
					if (skillid ==MapTimer) { //opqlo 地圖狀態
						final MapTimeTable table = MapTimeTable.getInstance();
						if(table.isInMap(pc.getMapId())){
							pc.setSkillEffect(skillid, remaining_time * 1000);
							pc.sendPackets(new S_SystemMessage("你可以在此活動[ "+remaining_time+" ]秒。"));
						}else{
							pc.killSkillEffectTimer(MapTimer);
						}
						//	pc.sendPackets(new S_SkillIconGFX(71, remaining_time));//opqlo 特殊地圖計時顯示

						/*} else if (skillid >= COOKING_1_0_N && skillid <= COOKING_1_6_N
								|| skillid >= COOKING_1_0_S && skillid <= COOKING_1_6_S
								|| skillid >= COOKING_2_0_N && skillid <= COOKING_2_6_N
								|| skillid >= COOKING_2_0_S && skillid <= COOKING_2_6_S
								|| skillid >= COOKING_3_0_N && skillid <= COOKING_3_6_N
								|| skillid >= COOKING_3_0_S && skillid <= COOKING_3_6_S) { // 料理(デザートは除く)
							L1Cooking.eatCooking(pc, skillid, remaining_time);*/
						//TODO 暗影閃避 鏡像byajackk2001
					} else if (skillid == L1SkillId.MIRROR_IMAGE || skillid == L1SkillId.UNCANNY_DODGE ) { //TODO 鏡像 暗影閃避
						final int time = remaining_time / 16;
						pc.addDodge((byte) 5); //TODO 閃避率 + 50%
						pc.sendPackets(new S_PacketBox(88, pc.getDodge()));
						pc.sendPackets(new S_PacketBox(21, time));
						pc.setSkillEffect(skillid, time * 16 * 1000);
						//TODO 暗影閃避 鏡像byajackk2001
					}else if(skillid == 98765432){
						pc.setSkillEffect(98765432, 1000);
					} else if(pc.getClanid() !=0 ){
						if( pc.getClan() !=null){
							final int castleId = pc.getClan().getCastleId();
							if(castleId!=0){
								if(!ServerWarExecutor.get().isNowWar(castleId)){
									final L1Castle castle = CastleTable.getInstance().getCastleTable(castleId);
									if(	skillid ==  狂暴打擊){
										castle.useCastleSkill((byte) 1, pc, null , remaining_time);
									}else if(skillid == 鋼鐵防禦){
										castle.useCastleSkill((byte)2, pc, null , remaining_time);
									}else if (skillid == 賞金獵人){
										castle.useCastleSkill((byte)3, pc, null , remaining_time);
									}else if(skillid == 狩獵專長){
										castle.useCastleSkill((byte)4, pc, null , remaining_time);
									}
								}
							}
						}
					} else {
						final L1SkillUse l1skilluse = new L1SkillUse();
						l1skilluse.handleCommands(pc,skillid, pc.getId(), pc.getX(), pc.getY(), null,remaining_time, L1SkillUse.TYPE_LOGIN);
					}
					break;
				}

			}
		} catch (final SQLException e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
		} finally {
			SQLUtil.close(rs);
			SQLUtil.close(pstm);
			SQLUtil.close(con);
		}
	}


	/**取得殷海薩的祝福*/
	private void getAinStatus(final L1PcInstance pc){
		try{
			final int ainOutTime = Config.RATE_AIN_OUTTIME;
			final int ainMaxPercent = Config.RATE_MAX_CHARGE_PERCENT;

			if (pc.getLevel() >= 49) { // TODO 49級以上 殷海薩的祝福紀錄
				if (pc.getMap().isSafetyZone(pc.getLocation())) {
					pc.setAinZone(1);
				} else {
					pc.setAinZone(0);
				}

				if (pc.getAinPoint() >= 1) {
					pc.sendPackets(new S_SkillIconExp(pc.getAinPoint()));// TODO 角色登入時點數大於1則送出
				}
				if (pc.getAinZone() == 1) {
					final 	Calendar cal = Calendar.getInstance();
					final long startTime = (cal.getTimeInMillis() - pc.getLastActive().getTime()) / 60000;

					if (startTime >= ainOutTime) {
						final long outTime = startTime / ainOutTime;
						final long saveTime = outTime + pc.getAinPoint();
						if (saveTime >= 1 && saveTime <= ainMaxPercent) {
							pc.setAinPoint((int) saveTime);
						} else if (saveTime > ainMaxPercent) {
							pc.setAinPoint(ainMaxPercent);
						}
					}
				}
			}
		} catch (final Exception e) {
			_log.log(Level.WARNING,e.getLocalizedMessage(), e);
		}
	}

	/**
	 * 其它數據
	 *
	 * @param pc
	 * @throws Exception
	 */
	private void getOther(final L1PcInstance pc){
		try {

			L1World.getInstance().addVisibleObject(pc);
			// TODO 初始能力加成
			pc.sendPackets( new S_InitialAbilityGrowth(pc));

			pc.sendPackets(new S_Unknown1());
			pc.sendPackets(new S_Unknown2());

			//TODO 暗影閃避 鏡像byajackk2001
			pc.sendPackets(new S_PacketBox(88, pc.getDodge())); //TODO 正
			pc.sendPackets(new S_PacketBox(101, pc.getNdodge())); //TODO 負
			//TODO 暗影閃避 鏡像byajackk2001

			pc.beginGameTimeCarrier();


			//_pc.sendPackets(new S_ActiveSpells(_pc));
			pc.sendPackets(new S_Karma(pc)); //TODO カルマ値を表示

			pc.sendPackets(new S_OwnCharStatus(pc));

			pc.sendPackets(new S_MapID(pc.getMapId(), pc.getMap().isUnderwater()));

			pc.sendPackets(new S_OwnCharPack(pc));

			pc.sendPackets(new S_SPMR(pc));

			// XXX タイトル情報はS_OwnCharPackに含まれるので多分不要
			pc.sendPacketsAll(new S_CharTitle(pc.getId(), pc.getTitle()));

			pc.sendVisualEffectAtLogin(); // クラウン、毒、水中等の視覚効果を表示

			pc.sendPackets(new S_Weather(L1World.getInstance().getWeather()));

			//	_pc.startObjectAutoUpdate();

			pc.onChangeLawful();//opqlo 戰鬥特化暫時置放

		} catch (final Exception e) {
			_log.log(Level.WARNING,e.getLocalizedMessage(), e);
		}
	}

	@Override
	public String getType() {
		return C_LOGIN_TO_SERVER;
	}
	private void items(final L1PcInstance pc) {
		// DBからキャラクターと倉庫のアイテムを読み込む
		CharacterTable.getInstance().restoreInventory(pc);
		//opqlo 新增GM 可以交易 不能交易物品(需修改封包傳送方式)
		//	if(_pc.isGm()||_pc.isMonitor()){
		pc.sendPackets(new S_InvList(pc.getInventory().getItems(), 0));
		//	}else{
		//		_pc.sendPackets(new S_InvList(_pc.getInventory().getItems()));
		//	}
		//opqlo 新增GM 可以交易 不能交易物品(需修改封包傳送方式)
	}
	/**讀取角色任務表*/
	private void loadQuest(final L1PcInstance pc){

		Connection con = null;
		PreparedStatement pstm = null;
		ResultSet rs = null;
		final L1Quest quest = pc.getQuest();
		try {
			con = DatabaseFactory.get().getConnection();
			pstm = con.prepareStatement("SELECT * FROM character_quests WHERE char_id=?");
			pstm.setInt(1, pc.getId());
			rs = pstm.executeQuery();
			while (rs.next()) {
				quest.setQuest(new Integer(rs.getInt(2)),new Integer(rs.getInt(3)));
			}

		} catch (final SQLException e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage()+"任務載入錯誤:"+pc.getName(), e);
			pc.getNetConnection().close();
		} finally {
			SQLUtil.close(rs , pstm , con);
		}
	}

	/**
	 * 取得婚姻資料
	 *
	 * @param pc
	 */
	private void marriage(final L1PcInstance pc) {
		try {
			final int partnerId = pc.getPartnerId();
			if (partnerId != 0) { // 結婚中----opqlo 角色刪除或不存在此編號 自動離婚
				if(	CharObjidTable.get().isChar(partnerId) == null){
					pc.setPartnerId(0);
					pc.save(); // DBにキャラクター情報を書き込む
					pc.sendPackets(new S_ServerMessage(662)); // \f1あなたは結婚していません。
				}
				final L1PcInstance partner = (L1PcInstance)L1World.getInstance().findObject(partnerId);
				if (partner != null && partner.getPartnerId() != 0) {
					if (partnerId == partner.getId() && partner.getPartnerId() == pc.getId()) {
						// 548 你的情人目前正在線上。
						pc.sendPackets(new S_ServerMessage(548));
						// 549 你的情人上線了!!
						partner.sendPackets(new S_ServerMessage(549));
					}
				}
			}
		} catch (final Exception e) {
			_log.log(Level.WARNING,e.getLocalizedMessage(), e);
		}
	}
	/**玩家上線通知GM*/
	private void PlayerOnline(final L1PcInstance pc , final ClientThread client){
		if (!Config.WHO_ONLINE_MSG_ON) {return;}
		try {
			final Collection<L1PcInstance> allGM = L1World.getInstance().getAllGms();
			if(!allGM.isEmpty()){
				String msg = null;
				if (pc.isCrown()) {
					msg = "王子";
				} else if (pc.isKnight()) {
					msg = "騎士";
				} else if (pc.isElf()) {
					msg = "妖精";
				} else if (pc.isWizard()) {
					msg = "法師";
				} else if (pc.isDarkelf()) {
					msg = "黑妖";
				} else if (pc.isDragonKnight()) {
					msg = "龍騎士";
				} else if (pc.isIllusionist()) {
					msg = "幻術士";
				}
				final StringBuilder sb=new StringBuilder().append("(玩家").append(pc.getName()).append( ")(帳號").append(client.getAccountName()).append(")(IP").append(client.getIp().toString()).append(")(職業").append( msg).append(")(上線)");
				final String Onlinemsg = sb.toString();
				for (final L1PcInstance GM : allGM) {
					if (GM.isOverHeadXX()){// xxyyzzxyz & 夜貓子
						GM.sendPackets(new S_SystemMessage(Onlinemsg));
					}
				}
				sb.delete(0, sb.length());
				msg = null;
			}
		} catch (final Exception e) {
			_log.log(Level.WARNING,e.getLocalizedMessage(), e);
		}
	}
	/**
	 * 取得殘留寵物資訊
	 *
	 * @param pc
	 */
	private void serchSummon(final L1PcInstance pc) {
		final Collection<L1SummonInstance> summons = WorldSummons.get().all();
		if (summons.size() > 0) {
			for (final L1SummonInstance summon : summons) {
				if (summon.getMaster().getId() == pc.getId()) {
					summon.setMaster(pc);
					pc.addPet(summon);
					for (final L1PcInstance visiblePc : L1World.getInstance().getVisiblePlayer(summon)) {
						visiblePc.sendPackets(new S_SummonPack(summon, visiblePc));
					}
				}
			}
		}
	}

	private void skills(final L1PcInstance pc) {
		try {
			final ArrayList<L1UserSkillTmp> skillList = CharSkillReading.get().skills(pc.getId());

			final int[] skills = new int[28];

			if (skillList != null) {
				if (skillList.size() > 0) {
					for (final L1UserSkillTmp userSkillTmp : skillList) {
						// 取得魔法資料
						final L1Skills skill = SkillsTable.getInstance().getTemplate(userSkillTmp.get_skill_id());
						skills[skill.getSkillLevel() - 1] += skill.getId();
						//_log.error("skill.getSkillLevel() - 1" + (skill.getSkillLevel() - 1) + " skill.getId():" + skill.getId());
					}
					// 送出資料
					pc.sendPackets(new S_AddSkill(pc, skills));
				}
			}

		} catch (final Exception e) {
			_log.log(Level.SEVERE ,e.getLocalizedMessage(), e);
		}
	}

	@Override
	public void start(final byte[] decrypt, final ClientThread client) {
		try {
			// 資料載入
			this.read(decrypt);
			/*
			//計算程式執行時間
			double startTime,endTime,totTime;
		    startTime = System.currentTimeMillis();
			 */
			 final String login = client.getAccountName();
			 if (client.getActiveChar() != null) {
				 _log.info("角色ID重複登入(" + client.getIp().toString() + " / "+login+" )已強制中斷連線。");
				 client.close();
				 return;
			 }

			 final String charName = this.readS();
				if(charName == null){
					return;
				}
			 final L1PcInstance pc = L1PcInstance.load(charName);
			 GameServer.getInstance().addOnlinePc(client, pc);


			 if (pc == null || !login.equals(pc.getAccountName())) {
				 _log.info("無效登入要求: " + charName + " 帳號(" + login + ", " + client.getIp().toString() + ")");
				 client.close();
				 return;
			 }

			 /**opqlo防多登*/
			 for (final L1PcInstance pctmp : L1World.getInstance().getAllPlayers()) {
				 if (login.equals(pctmp.getAccountName())) {
					 _log.info("存在相同角色登入，角色無法登入: char=" + charName + " account=" + login + " host=" + client.getIp().toString());
					 final ClientThread Targetclient = pctmp.getNetConnection();
					 if(Targetclient !=null){
						 Targetclient.close();
					 }else{
						 QuitGame.quitGame(pctmp);
					 }
					 client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_ACCOUNT_IN_USE));
					 client.close();
					 return;
				 }
			 }
			 /**opqlo防多登*/

			 pc.setNetConnection(client);// 登記封包接收組
//			 pc.setPacketOutput(client);// 登記封包發送組
			 pc.setPacketOutput(client.out());// 登記封包發送組

			 client.setActiveChar(pc);
			 _log.info("【進入遊戲】 角色名稱：" + charName + " 玩家帳號：" + login + " 玩家IP："+ client.getIp().toString());

			 /**所在座標位置資料判斷*/
			 this.BackRestart(pc);

			 final int currentHpAtLoad = pc.getCurrentHp();
			 final int currentMpAtLoad = pc.getCurrentMp();

			 pc.clearSkillMastery();// 清除技能資訊
			 pc.setOnlineStatus(1);// 設定連線狀態
			 CharacterTable.updateOnlineStatus(pc);
			 L1World.getInstance().storeObject(pc);



			 /**其它數據*/
			 this.getOther(pc);

			 /**讀取角色道具*/
			 this.items(pc);

			 /**取得記憶座標資料*/
			 this.bookmarks(pc);

			 /**讀取角色任務表*/
			 this.loadQuest(pc);

			 /**取得角色魔法技能資料*/
			 this.skills(pc);

			 /**取得物品與魔法特殊效果*/
			 this.buff(pc);

			 pc.turnOnOffLight();

			 if (pc.getCurrentHp() > 0) {
				 pc.setDead(false);
				 pc.setStatus(0);
			 } else {
				 pc.setDead(true);
				 pc.setStatus(ActionCodes.ACTION_Die);
			 }

			 /**殷海薩的祝福*/
			 this.getAinStatus(pc);



			 if (pc.get_food() >= 225) {//TODO LOLI 生存吶喊
				 final Calendar cal = Calendar.getInstance();
				 final long h_time = cal.getTimeInMillis() / 1000;//TODO 換算為秒
				 pc.set_h_time(h_time);//TODO 紀錄登入時間
			 }

			 // TODO　在線一段時間給物品　by 阿傑
			 if (Config.GITorF) {
				 pc.setSkillEffect(Online_Bonus, Config.GIT * 60000);// 3分鐘
			 }
			 // TODO　在線一段時間給物品　by 阿傑
			 
			 /**opqlo 檢查身上是否有到期須刪除的物品*/
			 pc.setSkillEffect(checkDeleteItem, 60000);

			 // TODO 調整能力值上限
			 /*if (pc.getLevel() >= 51 && pc.getLevel() - 50 > pc.getBonusStats()) {
				if ((pc.getBaseStr() + pc.getBaseDex() + pc.getBaseCon()
						+ pc.getBaseInt() + pc.getBaseWis() + pc.getBaseCha()) < (Config.BONUS_STATS1 * 6)) {
					pc.sendPackets(new S_bonusstats(pc.getId(), 1));
				}
			}*/
			 // TODO 調整能力值上限

			 /**取回快速鍵紀錄*/
			 if (Config.CHARACTER_CONFIG_IN_SERVER_SIDE) {
				 pc.sendPackets(new S_CharacterConfig(pc.getId()));
			 }
			 /**取得殘留寵物資訊*/
			 this.serchSummon(pc);

			 /**檢查城堡戰爭狀態*/
			 ServerWarExecutor.get().checkCastleWar(pc);

			 /**玩家上線通知GM*/
			 this.PlayerOnline(pc , client);

			 /**取得血盟資料與戰爭狀態*/
			 this.war(pc);

			 /**取得婚姻資料*/
			 this.marriage(pc);

			 if (currentHpAtLoad > pc.getCurrentHp()) {
				 pc.setCurrentHp(currentHpAtLoad);
			 }
			 if (currentMpAtLoad > pc.getCurrentMp()) {
				 pc.setCurrentMp(currentMpAtLoad);
			 }
		

//			 if(_pc.getClanid()!=0){
//				 _pc.sendPackets(new S_Emblem(_pc.getClanid()));
//				 L1World.getInstance().broadcastPacketToAll(new S_Emblem(_pc.getClanid()));
//
//			 }
			 /**經驗值更新開始*/
			 //_pc.beginExpMonitor();

				// 取回快速鍵紀錄
				final L1Config config =
					CharacterConfigReading.get().get(pc.getId());
				if (config != null) {
					pc.sendPackets(new S_PacketBoxConfig(config));
				}
				
				/**PC 可見物更新處理*/
				 pc.startObjectAutoUpdate();
				 
				 pc.startHpRegeneration();
				 pc.startMpRegeneration();


			client.CharReStart(false);
			 pc.sendPackets(new S_OwnCharStatus(pc));

			 /**opqlo 掛機檢測次數*/
			 pc.setAICount(Random.nextInt(300)+300);

			 /** 處理新手保護系統(遭遇的守護)狀態資料的變動*/
			 pc.checkNoviceType();


			 /**opqlo 斷線重登會自動加入原本隊伍*/
//			 pc.ReSetPartyID();

			 pc.sendPackets(new S_Mail(pc.getName(), 0));
			 pc.sendPackets(new S_Mail(pc.getName(), 1));

			 /**opqlo 取得時空裂痕*/
			 if(CrackTime.get().getCrackLocName() !=null){
				 pc.sendPackets(new S_SystemMessage(CrackTime.get().getCrackLocName()));
			 }

			 if(pc.get_metempsychosis() <=30 && pc.getExp() ==0){
				 快速50級.get().set(pc);
			 }


			 if(pc.getQuest().get_step(L1Quest.QUEST_opqlo新手保護) ==0){
				 pc.getQuest().set_step(L1Quest.QUEST_opqlo新手保護, 1);
			 }
			 if(pc.getQuest().get_step(L1Quest.QUEST_opqlo新手保護)==1){
				 pc.sendPackets(new S_SystemMessage("\\aD處於新手保護階段，遭PVP死亡不噴裝。"));
			 }
			 if(pc.isChangeName()){
				 pc.sendPackets(new A_ColorMessage(1,"請在對話框輸入:\n在你要的名稱前加上[新名稱]\n例如:新名稱"+pc.getName()+"\n變更後角色名稱為:"+pc.getName()));
			 }
			
			 //如果使用日方架構
				 /**開始更新經驗值*/
			 pc.beginExpMonitor();
			 
			 if(pc.getLevel() ==99){
					if(pc.getInventory().findItemId(43000) ==null){
						final L1Item l1item = ItemTable.getInstance().getTemplate(43000);
						if (l1item != null) {
							pc.getInventory().storeItem(43000, 1);
							pc.sendPackets(new S_ServerMessage(403, l1item.getName()));
						} else {
							pc.sendPackets(new S_SystemMessage("返生藥水取得失敗。"));
						}
				}
			 }
				if (pc.getWeapon() != null) {
					pc.sendPacketsAll(new S_CharVisualUpdate(pc));
				}
				 /**檢查地獄時間*/
				 if (pc.getHellTime() > 0 || pc.get_PKcount()>=300) {
					 pc.beginHell();
				 }
			 /*
			 //把要測試的程式放到endTime前面
	        endTime = System.currentTimeMillis();
	        //取得程式結束的時間
	        totTime = endTime - startTime;
	        //計算經過多久
	        System.out.println("Using Time: " + totTime/1000+" sec");
	        System.out.println("Using Time: " + totTime+" ms");
			  */
		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);

		} finally {
			this.over();
		}
	}
	/**
	 * 取得血盟 與 血盟戰爭資料
	 *
	 * @param pc
	 */
	private void war(final L1PcInstance pc) {
		try {
			if (pc.getClanid() != 0) { // 血盟資料不為0
				final L1Clan clan = WorldClan.get().getClan(pc.getClanname());
				if (clan != null) {
					// 判斷血盟名稱相等 雨 血盟編號相等
					if (pc.getClanid() == clan.getClanId() &&
							pc.getClanname().toLowerCase().equals(clan.getClanName().toLowerCase())) {
						final L1PcInstance[] clanMembers = clan.getOnlineClanMember();
						for (final L1PcInstance clanMember : clanMembers) {
							if (clanMember.getId() != pc.getId()) {
								// 843 血盟成員%0%s剛進入遊戲。
								clanMember.sendPackets(new S_ServerMessage(843, pc.getName()));
							}
						}

						final int clanMan = clan.getOnlineClanMember().length;
						pc.sendPackets(new S_ServerMessage("\\fU線上血盟成員:" + clanMan));


						// 送出盟輝
						final L1EmblemIcon emblemIcon = ClanEmblemReading.get().get(clan.getClanId());
						if (emblemIcon != null) {
							pc.sendPackets(new S_Emblem(emblemIcon));
						}

						// 目前全部戰爭資訊取得
						for (final L1War war : WorldWar.get().getWarList()) {
							final boolean ret = war.checkClanInWar(pc.getClanname());
							if (ret) { // 是否正在戰爭中
								final String enemy_clan_name = war.getEnemyClanName(pc.getClanname());
								if (enemy_clan_name != null) {
									// \f1目前你的血盟與 %0 血盟交戰當中。
									pc.sendPackets(new S_War(8, pc.getClanname(), enemy_clan_name));
								}
								break;
							}
						}
					}

				} else {
					pc.setClanid(0);
					pc.setClanname("");
					pc.setClanRank(0);
					pc.save();
				}
			}

		} catch (final Exception e) {
			_log.log(Level.SEVERE , e.getLocalizedMessage(), e);
		}
	}
}
